package com.hulk.dryad.persistence;

import cn.hutool.core.convert.Convert;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.google.common.base.Splitter;
import com.hulk.dryad.persistence.entity.SuperEntity;
import com.hulk.dryad.manage.boot.injector.SuperService;
import com.hulk.dryad.manage.boot.injector.impl.SuperServiceImpl;


import java.io.File;
import java.util.*;

/**
 * <p>
 * 代码生成器父类
 * </p>
 *
 * @author hulk
 */
public class SuperGenerator {

	private  final  static String DRIVER_NAME="com.mysql.cj.jdbc.Driver";

	private  final  static String DB_USERNAME="root";
	private  final  static String DB_PASSWORD="root123";
	private  final  static String DB_URL="jdbc:mysql://127.0.0.1:3306/dryad";

    private  final  static String MODULE_PERSISTENCE_NAME = "dryad-persistence";
	private  final  static String MODULE_MANAGE_NAME = "dryad-manage";
    private  final  static String ROOT_PACKAGE = "com.hulk.dryad";
    private  final  static String SUPER_MAPPER = ROOT_PACKAGE + ".persistence.injector.basic.mapper.SuperMapper";
    private  final  static String PACKAGE_MAPPER_DIR = "/com/hulk/dryad/persistence/mapper/";
	private  final  static String PACKAGE_ENTITY_DIR = "/com/hulk/dryad/persistence/entity/";




    /**
     * 获取TemplateConfig
     *
     * @return
     */
    protected TemplateConfig getTemplateConfig() {
        return new TemplateConfig().setXml(null);
    }

    /**
     * 获取InjectionConfig
     *
     * @return
     */
    protected InjectionConfig getInjectionConfig() {

        FileOutConfig  xmlConfig = new FileOutConfig(
                "/templates/mapper.xml.vm") {
            // 自定义输出文件目录
            @Override
            public String outputFile(TableInfo tableInfo) {
                return getResourcePath() + "/mapper/" + tableInfo.getEntityName() + "Mapper.xml";
            }
        };

        FileOutConfig  javaMapperConfig = new FileOutConfig(
                "/templates/mapper.java.vm") {
            // 自定义输出文件目录
            @Override
            public String outputFile(TableInfo tableInfo) {
                return getJavaPath() + PACKAGE_MAPPER_DIR + tableInfo.getEntityName() + "Mapper.java";

            }
        };
		FileOutConfig  javaEntityConfig = new FileOutConfig(
				"/templates/entity.java.vm") {
			// 自定义输出文件目录
			@Override
			public String outputFile(TableInfo tableInfo) {
				return getJavaPath() + PACKAGE_ENTITY_DIR + tableInfo.getEntityName() + ".java";

			}
		};
        List<FileOutConfig> ls = new ArrayList<>();
        ls.add(xmlConfig);
        ls.add(javaMapperConfig);
		ls.add(javaEntityConfig);
        return new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                this.setMap(map);
            }
        }.setFileOutConfigList(ls);
    }

    /**
     * 获取PackageConfig
     *
     * @return
     */
    protected PackageConfig getPackageConfig() {
        return new PackageConfig()
                .setParent(ROOT_PACKAGE)
               //  .setModuleName("upms")
                .setEntity("persistence.entity")
                .setMapper("persistence.mapper")
                .setXml("mapper")
                .setServiceImpl("persistence.service.impl")
                .setService("persistence.service")      //本项目没用，生成之后删掉
                .setController("web.control")
                ;    //本项目没用，生成之后删掉
    }

    /**
     * 获取StrategyConfig
     *
     * @param tableName
     * @return
     */
    protected StrategyConfig getStrategyConfig(String tableName) {
		List<String> split = Splitter.on(StrUtil.COMMA).trimResults().omitEmptyStrings().splitToList(tableName);
        //List<String> split = StrSpliter.split(tableName, ',', 0, true, true);
        return new StrategyConfig()
                .setCapitalMode(false)// 全局大写命名
                .setTablePrefix("t_")// 去除前缀
                .setNaming(NamingStrategy.underline_to_camel)// 表名生成策略
                .setColumnNaming(NamingStrategy.underline_to_camel)// 列名生成策略
                // 需要生成的表
                .setInclude(Convert.toStrArray(split))
                //自定义实体父类
                .setSuperEntityClass(SuperEntity.class)
                // 自定义 mapper 父类
                .setSuperMapperClass(SUPER_MAPPER)
                // 自定义实体，公共字段
                .setSuperEntityColumns("reversion")
                .setVersionFieldName("reversion")
				//Service抽象类
				.setSuperServiceClass(SuperService.class)
				.setSuperServiceImplClass(SuperServiceImpl.class)
                //逻辑删除列
                .setLogicDeleteFieldName("archived_flag")
                .setTableFillList(getTableFills())
                // 【实体】是否生成字段常量（默认 false）
                .setEntityColumnConstant(false)
                //实体】是否为构建者模型（默认 false）
                //.setEntityBuilderModel(true)
                // 【实体】是否为构建者模型（默认 false）
                .setChainModel(true)
                // 【实体】是否为lombok模型（默认 false）<a href="https://projectlombok.org/">document</a>
                .setEntityLombokModel(true)
                // Boolean类型字段是否移除is前缀处理
                .setEntityBooleanColumnRemoveIsPrefix(true)
                .setEntityTableFieldAnnotationEnable(true)
                // 自定义 controller 父类
                //.setSuperControllerClass("com.hulk.buff.upms.web.control.AbsBaseCtl")
                .setRestControllerStyle(true)
                .setControllerMappingHyphenStyle(true);

    }

    /**
     * 获取TableFill策略
     *
     * @return
     */
    protected List<TableFill> getTableFills() {
        // 自定义需要填充的字段
        List<TableFill> tableFillList = new ArrayList<>();
        tableFillList.add(new TableFill("created_time", FieldFill.INSERT));
        tableFillList.add(new TableFill("updated_time", FieldFill.INSERT_UPDATE));
		tableFillList.add(new TableFill("created_by", FieldFill.INSERT));
		tableFillList.add(new TableFill("updated_by", FieldFill.INSERT_UPDATE));
        tableFillList.add(new TableFill("reversion", FieldFill.INSERT_UPDATE));
        return tableFillList;
    }

    /**
     * 获取DataSourceConfig
     *
     * @return
     */
    protected DataSourceConfig getDataSourceConfig() {
        return new DataSourceConfig()
                .setDbType(DbType.MYSQL)// 数据库类型
                .setTypeConvert(new MySqlTypeConvert() {
                    @Override
                    public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
                        if (fieldType.toLowerCase().equals("date")) {
                            return DbColumnType.LOCAL_DATE;
                        }
                        if (fieldType.toLowerCase().equals("time")) {
                            return DbColumnType.LOCAL_TIME;
                        }
                        if (fieldType.toLowerCase().equals("datetime")) {
                            return DbColumnType.LOCAL_DATE_TIME;
                        }
                        return super.processTypeConvert(globalConfig, fieldType);
                    }
                })
                .setDriverName(DRIVER_NAME)
                .setUsername(DB_USERNAME)
                .setPassword(DB_PASSWORD)
                .setUrl(DB_URL);
    }

    /**
     * 获取GlobalConfig
     *
     * @return
     */
    protected GlobalConfig getGlobalConfig() {
        return new GlobalConfig()
                .setOutputDir(getJavaPath())//输出目录
                .setFileOverride(true)// 是否覆盖文件
                .setActiveRecord(true)// 开启 activeRecord 模式
                .setEnableCache(false)// XML 二级缓存
                .setBaseResultMap(false)// XML ResultMap
                .setBaseColumnList(false)// XML columList
                .setKotlin(false) //是否生成 kotlin 代码
                .setOpen(true)
                .setAuthor("hulk") //作者
                //自定义文件命名，注意 %s 会自动填充表实体属性！
                .setIdType(IdType.ASSIGN_ID)
                .setDateType(DateType.TIME_PACK)
                .setControllerName("%sController")
                .setServiceName("%sService")
                .setServiceImplName("%sServiceImpl")
                .setMapperName("%sMapper")
                .setXmlName("%sMapper");
        //.setEntityName("%s");
    }


    /**
     * 获取根目录
     *
     * @return
     */
    private String getRootPath() {
        return new File(SuperGenerator.class.getClassLoader().getResource("").getFile()).getParentFile().getParentFile().getParent();
    }

    /**
     * 获取JAVA目录
     *
     * @return
     */
    protected String getJavaPath() {
        return getRootPath() + "/" + MODULE_PERSISTENCE_NAME + "/src/main/java";
    }

    /**
     * 获取Resource目录
     *
     * @return
     */
    protected String getResourcePath() {
        return getRootPath() + "/" + MODULE_PERSISTENCE_NAME + "/src/main/resources";
    }

    /**
     * 获取AutoGenerator
     *
     * @param tableName
     * @return
     */
    protected AutoGenerator getAutoGenerator(String tableName) {
        return new AutoGenerator()
                // 全局配置
                .setGlobalConfig(getGlobalConfig())
                // 数据源配置
                .setDataSource(getDataSourceConfig())
                // 策略配置
                .setStrategy(getStrategyConfig(tableName))
                // 包配置
                .setPackageInfo(getPackageConfig())
                // 注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值
                .setCfg(getInjectionConfig())
                .setTemplate(getTemplateConfig());
    }

}
